unit data_MainDataModule;

interface

uses
  SysUtils,
  Classes,
  DB,
  DBTables,
  DBClient,
  Provider,
  //
  // my units
  //
  unit_CSVFile,
  //
  // 3rd party components
  //
  kbmMemTable;

type
  TFieldDesc = record
    Name: WideString;
    DataType: TFieldType;
    Size: Integer;
    Required: Boolean;
  end;

  TIndexDesc = record
    Name: WideString;
    Fields: WideString;
    Options: TIndexOptions;
  end;
  //
  TTableFields = array of TFieldDesc;
  TTableIndexes = array of TIndexDesc;
  //
  TdmMainDB = class(TDataModule)
    dsMainTable: TDataSource;
    procedure DataModuleDestroy(Sender: TObject);
    procedure DataModuleCreate(Sender: TObject);
  private
    { Private declarations }
    FGenesisTable: TkbmMemTable;
    FLocalTable: TkbmMemTable;
    FCSVFile: TCSVFile;
  protected
    function CreateTable(var Table: TkbmMemTable; const TableName: WideString;
        const FieldDesc: array of TFieldDesc;
        const IndexDesc: array of TIndexDesc): Boolean;

  public
    function CreateTables: Boolean;
    procedure LoadTableFromCSV(const CSVFileName: AnsiString; Table: TDataSet);
    { Public declarations }
    property GenesisTable: TkbmMemTable read FGenesisTable write FGenesisTable;
    property LocalTable: TkbmMemTable read FLocalTable write FLocalTable;

  end;

var
  dmMainDB: TdmMainDB;

implementation

{$R *.dfm}
const
//
// Genesis table data
//
GenesisTableFields: array [1 .. 5] of TFieldDesc = (
  (Name: 'ID';           DataType: ftInteger;    Size: 0;   Required: true),
  (Name: 'Filename';     DataType: ftWideString; Size: 255; Required: false),
  (Name: 'Filesize';     DataType: ftLargeint;   Size: 0;   Required: true),
  (Name: 'MD5';          DataType: ftString;     Size: 32;  Required: true),
  (Name: 'CRC32';        DataType: ftString;     Size: 8;   Required: false)
);
//
GenesisTableIndexes: array [1..4] of TIndexDesc = (
  (Name: 'ID_Index';     Fields: 'ID';         Options: [ixPrimary, ixUnique]),
  (Name: 'FileName_Index'; Fields: 'Filename'; Options: [ixCaseInsensitive]),
  (Name: 'FileSize_Index'; Fields: 'FileSize'; Options: [ixCaseInsensitive]),
  (Name: 'MD5_Index';      Fields: 'MD5';      Options: [])
);

//------------------------------------------------------------------------------
// function TdmMainDB.CreateTable
//   Create table data structure (fields, indices)
// Parameters:
//   var   Table      : TkbmMemTable        - TkbmMemTable exemplar to proceed
//   const TableName  : WideString          - table name
//   const FieldDesc  : array of TFieldDesc - fields specification
//   const IndexDesc  : array of TIndexDesc - indices specification
// Result: Boolean
//   True, if table structure created successfully; False otherwise
//------------------------------------------------------------------------------
function TdmMainDB.CreateTable(var Table: TkbmMemTable; const TableName: WideString;
  const FieldDesc: array of TFieldDesc;
  const IndexDesc: array of TIndexDesc): Boolean;
var
  i: Integer;
begin
  Result := False;
  if Table = nil then begin
    Exit;
  end;
  Table.Active := False;
  Table.DeleteTable;
  try
    if not (Table is TkbmMemTable) then begin
//      Table.TableName := TableName;
//      Table.DatabaseName := FDBMain.DatabaseName;
    end;
    //
    // Fill fields data structure
    //
    for i := 0 to High(FieldDesc) do
      Table.FieldDefs.Add(
        FieldDesc[i].Name,
        FieldDesc[i].DataType,
        FieldDesc[i].Size,
        FieldDesc[i].Required
      );
    //
    // Fill indices data structure
    //
    for i := 0 to High(IndexDesc) do
      Table.IndexDefs.Add(
        IndexDesc[i].Name,
        IndexDesc[i].Fields,
        IndexDesc[i].Options
      );
    //
    // Create table with specified data structure
    //
    Table.CreateTable;
    Result := True;
  finally
  end;
end;
//------------------------------------------------------------------------------
// function TdmMainDB.CreateTables
//   Creates internal DB tables
// Parameters:
//   None
// Result: Boolean
//   True, if internal tables created;
//   False, if error occured while creating tables
//------------------------------------------------------------------------------
function TdmMainDB.CreateTables: Boolean;
var
  bTableCreated: Boolean;
begin
  Result := True;
  //
  // Create FGenesisTable, set result
  //
  bTableCreated := CreateTable(FGenesisTable, 'genesis', GenesisTableFields,
    GenesisTableIndexes);
  Result := Result and bTableCreated;
end;
//------------------------------------------------------------------------------
// procedure TdmMainDB.DataModuleDestroy
//   free memory and destroy internal in-memory tables
// Parameters:
//   Sender: TObject
// Result:
//   None
//------------------------------------------------------------------------------
procedure TdmMainDB.DataModuleDestroy(Sender: TObject);
begin
  FreeAndNil(FCSVFile);
  FreeAndNil(FLocalTable);
  FreeAndNil(FGenesisTable);
  //
  FreeAndNil(FGenesisTable);
end;
//------------------------------------------------------------------------------
// procedure TdmMainDB.DataModuleCreate
//   Create internal data module classes (in-memory tables, csv file class),
//     intialize class fields and properties
// Parameters:
//   Sender: TObject
// Result:
//   None
//------------------------------------------------------------------------------
procedure TdmMainDB.DataModuleCreate(Sender: TObject);
begin
  //
  // Create exemplars of internal memory tables
  //
  FGenesisTable := TkbmMemTable.Create(Self);
  FLocalTable := TkbmMemTable.Create(Self);
  FCSVFile := TCSVFile.Create;
  //
  // Create internal memory tables structure
  //
  CreateTables;
end;
//------------------------------------------------------------------------------
// procedure TdmMainDB.LoadTableFromCSV
//   Load data from CSV File into specified dataset
// Parameters:
//   const CSVFileName: AnsiString - csv filename with absolute path
//         Table: TDataSet - dataset for data import   
// Result: 
//   None
//------------------------------------------------------------------------------
procedure TdmMainDB.LoadTableFromCSV(const CSVFileName: AnsiString; Table:
    TDataSet);
begin
  FCSVFile.Clear;
  FCSVFile.LoadCSVFile(CSVFileName);
  //
  TkbmMemTable(Table).EmptyTable;
  FCSVFile.ExportToTable(Table as TkbmMemTable);
  FCSVFile.Clear;
end;

end.
